#ifndef _FSMC_HW_H_
#define _FSMC_HW_H_

/**
 * 1、FSMC用于将AHB事务转换为合适的外部器件协议，支持SRAM(静态随机访问存储器)、
 *    ROM(只读存储器)、NOR Flash/OneNAND Flash、PSRAM(4个存储区域)
 * 2、有两个ECC硬件的NAND Flash存储区域，可检查8KB的数据
 * 3、所有器件共享地址、数据、和控制信号，但有各自的片选信号，FSMC同一时刻仅能
 *    访问一个器件
 * 4、BANK1：0x60000000，可连接4个NOR Flash/PSRAM，有4个片选信号
 *    BANK2：0x70000000，可连接1个NAND Flash器件
 *    BANK3：0x80000000，可连接1个NAND Flash器件
 *    BANK4：0x90000000，可连接PC卡设备
 * 5、NOR Flash/PSRAM 控制器：
 *      1、异步SRAM/ROM: 8B、16B、32B位宽
 *      2、PSRAM（ Cellular RAM）：异步、突发、复用或非复用
 *      3、NOR Flash：异步、突发、复用或非复用
 * 6、同步访问期间，只有读写事务发生时才会发出时钟
 *
 */

#include "soc.h"

typedef struct {
	_RW BCR1;    /*!< NOR/PSRAM chip-select control register(BCR), offset: 0x00 */
	_RW BTR1;    /*!< NOR/PSRAM chip-select timing register(BTR),  offset: 0x04 */
	_RW BCR2;    /*!< NOR/PSRAM chip-select control register(BCR), offset: 0x08 */
	_RW BTR2;    /*!< NOR/PSRAM chip-select timing register(BTR),  offset: 0x0C */
	_RW BCR3;    /*!< NOR/PSRAM chip-select control register(BCR), offset: 0x10 */
	_RW BTR3;    /*!< NOR/PSRAM chip-select timing register(BTR),  offset: 0x14 */
	_RW BCR4;    /*!< NOR/PSRAM chip-select control register(BCR), offset: 0x18 */
	_RW BTR4;    /*!< NOR/PSRAM chip-select timing register(BTR),  offset: 0x1C */
} FSMC_Bank1Struct;

typedef struct {
	_NU RESERVED0; /*!< Reserved, 0x100                                 */
	_RW BWTR1;     /*!< NOR/PSRAM write timing registers, offset: 0x104 */
	_NU RESERVED1; /*!< Reserved, 0x108                                  */
	_RW BWTR2;     /*!< NOR/PSRAM write timing registers, offset: 0x10C */
	_NU RESERVED2; /*!< Reserved, 0x110                                 */
	_RW BWTR3;     /*!< NOR/PSRAM write timing registers, offset: 0x114 */
	_NU RESERVED3; /*!< Reserved, 0x118                                 */
	_RW BWTR4;     /*!< NOR/PSRAM write timing registers, offset: 0x11C */
} FSMC_Bank1EStruct;

typedef struct {
	_RW PCR2;       /*!< NAND Flash control register 2,                       offset: 0x60 */
	_RW SR2;        /*!< NAND Flash FIFO status and interrupt register 2,     offset: 0x64 */
	_RW PMEM2;      /*!< NAND Flash Common memory space timing register 2,    offset: 0x68 */
	_RW PATT2;      /*!< NAND Flash Attribute memory space timing register 2, offset: 0x6C */
	_NU RESERVED0;  /*!< Reserved, 0x70                                                            */
	_RW ECCR2;      /*!< NAND Flash ECC result registers 2,                   offset: 0x74 */
	_NU RESERVED1;  /*!< Reserved, 0x78                                                            */
	_NU RESERVED2;  /*!< Reserved, 0x7C                                                            */
	_RW PCR3;       /*!< NAND Flash control register 3,                       offset: 0x80 */
	_RW SR3;        /*!< NAND Flash FIFO status and interrupt register 3,     offset: 0x84 */
	_RW PMEM3;      /*!< NAND Flash Common memory space timing register 3,    offset: 0x88 */
	_RW PATT3;      /*!< NAND Flash Attribute memory space timing register 3, offset: 0x8C */
	_NU RESERVED3;  /*!< Reserved, 0x90                                                            */
	_RW ECCR3;      /*!< NAND Flash ECC result registers 3,                   offset: 0x94 */
} FSMC_Bank23Struct;

typedef struct {
	_RW PCR4;       /*!< PC Card  control register 4,                       offset: 0xA0 */
	_RW SR4;        /*!< PC Card  FIFO status and interrupt register 4,     offset: 0xA4 */
	_RW PMEM4;      /*!< PC Card  Common memory space timing register 4,    offset: 0xA8 */
	_RW PATT4;      /*!< PC Card  Attribute memory space timing register 4, offset: 0xAC */
	_RW PIO4;       /*!< PC Card  I/O space timing register 4,              offset: 0xB0 */
} FSMC_Bank4Struct;

extern FSMC_Bank1Struct  SOC_FSMC_B1;
extern FSMC_Bank1EStruct SOC_FSMC_B1E;
extern FSMC_Bank23Struct SOC_FSMC_B23;
extern FSMC_Bank4Struct  SOC_FSMC_B4;

/**
 * SRAM/PSRAM片选控制寄存器
 */
#define FSMC_B1_BCRx_RESERVED          (0x1U<<7)  // 保留位
#define FSMC_B1_BCRx_MBKEN_DIS         (0x0U<<0)
#define FSMC_B1_BCRx_MBKEN_EN          (0x1U<<0)  // 使能该存储区域
#define FSMC_B1_BCRx_MUXEN_DIS         (0x0U<<1)
#define FSMC_B1_BCRx_MUXEN_EN          (0x1U<<1)  // 地址数据总线复用
#define FSMC_B1_BCRx_MTYP_SRAM_ROM     (0x0U<<2)  // SRAM、 ROM
#define FSMC_B1_BCRx_MTYP_PSRAM        (0x1U<<2)  // PSRAM（ Cellular RAM： CRAM）
#define FSMC_B1_BCRx_MTYP_NOR_NAND     (0x2U<<2)  // NOR Flash/OneNAND Flash
#define FSMC_B1_BCRx_MWID_8B           (0x0U<<4)
#define FSMC_B1_BCRx_MWID_16B          (0x1U<<4)  // 数据总线宽度16位
#define FSMC_B1_BCRx_FACCEN_DIS        (0x0U<<6)
#define FSMC_B1_BCRx_FACCEN_EN         (0x1U<<6)  // 使能NOR Flash访问

#define FSMC_B1_BCRx_BURSTEN_DIS       (0x0U<<8)
#define FSMC_B1_BCRx_BURSTEN_EN        (0x1U<<8)  // 使能突发访问模式，仅对同步突发存储器有效
#define FSMC_B1_BCRx_WAITPOL_LOW       (0x0U<<9)
#define FSMC_B1_BCRx_WAITPOL_HIGH      (0x1U<<9)  // 高电平有效，仅当ASYNCWAIT_EN该字段有效
#define FSMC_B1_BCRx_WRAPMOD_DIS       (0x0U<<10)
#define FSMC_B1_BCRx_WRAPMOD_EN        (0x1U<<10) // 使能直接回环突发，由于 CPU 和 DMA 无法生成环回突发传输，因此该位无效
#define FSMC_B1_BCRx_WAITCFG_PREV      (0x0U<<11) // NWAIT 信号在等待周期之前的一个数据周期有效
#define FSMC_B1_BCRx_WAITCFG_NOW       (0x1U<<11) // NWAIT 信号在等待周期期间有效（不适用于 Cellular RAM）
#define FSMC_B1_BCRx_WREN_DIS          (0x0U<<12) // FSMC 在存储区域内禁止了写入操作，如果进行写操作将报告 AHB 错误
#define FSMC_B1_BCRx_WREN_EN           (0x1U<<12)
#define FSMC_B1_BCRx_WAITEN_DIS        (0x0U<<13) // 禁止 NWAIT 信号（不考虑其电平，不在配置过的 Flash 延迟周期后插入等待周期）
#define FSMC_B1_BCRx_WAITEN_EN         (0x1U<<13) // 使能 NWAIT 信号（考虑其电平，如果使能，在配置过的 Flash 延迟周期后插入等待周期）（复位后的默认值）
#define FSMC_B1_BCRx_EXTMOD_DIS        (0x0U<<14) // 不考虑 FSMC_BWTR 寄存器中的值
#define FSMC_B1_BCRx_EXTMOD_EN         (0x1U<<14) // FSMC 可对 FSMC_BWTR 寄存器中的写入时间进行配置，此配置由 EXTMOD 位使能，进而使读取和写入操作采用不同时序
#define FSMC_B1_BCRx_ASYNCWAIT_DIS     (0x0U<<15) // 运行异步协议时不考虑 NWAIT 信号
#define FSMC_B1_BCRx_ASYNCWAIT_EN      (0x1U<<15) // 运行异步协议时考虑 NWAIT 信号，WAITPOL_LOW/HIGH用于设定WAIT信号的极性
#define FSMC_B1_BCRx_CPSIZE_NONE       (0x0U<<16) // 突发访问不需要拆分，对于PSRAM 1.5版本，不允许跨页地址的突发访问，需要FSMC拆分成多个小块进行访问，这个位段在中文手册中未描述，英文手册上有
#define FSMC_B1_BCRx_CPSIZE_128B       (0x1U<<16) // 拆分成128字节
#define FSMC_B1_BCRx_CPSIZE_256B       (0x2U<<16)
#define FSMC_B1_BCRx_CPSIZE_512B       (0x3U<<16)
#define FSMC_B1_BCRx_CPSIZE_1024B      (0x4U<<16)
#define FSMC_B1_BCRx_CBURSTRW_ASYNC    (0x0U<<19) // 始终在异步模式下进行写入操作
#define FSMC_B1_BCRx_CBURSTRW_SYNC     (0x1U<<19) // 在同步模式下进行写入操作,对于 Cellular RAM (PSRAM)，该位可在写操作时使能同步突发协议。读取访问期间同步突发协议的使能位为 FSMC_BCRx 寄存器中的 BURSTEN 位

/**
 * SRAM/NOR-Flash 片选时序寄存器，EXTMOD=1时，该寄存器仅控制读，BWTR控制写。
 * PSRAM (CRAM) 由于内部刷新而导致数据延时时间长度不确定。因此，这些存储器
 * 会在整个延迟阶段发送 NWAIT 信号，以便按照需要延长延迟。对于 PSRAM (CRAM)，
 * 字段 DATLAT 必须设置为 0，这样 FSMC 会立即退出延迟阶段，开始对存储器中的
 * NWAIT采样，然后在存储器准备就绪后开始读取或写入。此方法也适用于最新一代的
 * 同步 Flash，同早期 Flash 不同的是，此类 Flash 会发送 NWAIT信号
 *
 * BTR和BWTR字段是一致的，DATAST字段有一点不同，BWTR仅在EXTMOD=1时有效，且仅
 * 作用于写操作
 */
#define FSMC_B1_ByTRx_ADDSET_V_0_15D(v)  ((v)<<0)      // 地址设置阶段的持续时间，单位是Thclk，适用于SRAM、 ROM 和异步 NOR Flash 访问模式，在同步访问模式下，该值为无关值
#define FSMC_B1_ByTRx_ADDHLD_V_1_15D(v)  ((v)<<4)      // 地址保持阶段的持续时间，适用于模式D和复用访问在同步访问模式下，该值不使用，因为地址保持阶段的持续时间始终是 1 个存储器时钟周期
#define FSMC_B1_ByTRx_DATAST_V_1_255D(v) ((v)<<8)  // 数据阶段的持续时间，单位是Thclk，适用于SRAM、 ROM 和异步 NOR Flash 访问模式，在同步访问模式下，该值为无关值，写操作的时候，FSMC会多添加一个周期，也即实际写入的值应当减一
#define FSMC_B1_ByTRx_BUSTURN_V_0_15D(v) ((v)<<16)     // 在读写转换之间插入延时，对同一个静态存储器的两个连续的写操作之间不会插入延时，除非使用复用或模式D；对同一个静态存储器两个连续的异步读传输、异步读转向同步/异步写、不同静态存储器的异步读，都会额外插入1个延时；对同一个静态存储器两个来纳许的同步写、同步写转向同/异步读写、同/异步读写转向同步读，都会额外插入2个延时；对不同的静态存储器进行连续写、同步写转向同步读，都会额外插入3个延时
#define FSMC_B1_ByTRx_CLKDIV_V_2_16D(v)  (((v)-1)<<20) // 时钟分频，在异步 NOR Flash、 SRAM 或 ROM 访问模式下，该值为无关值。
#define FSMC_B1_ByTRx_DATLAT_V_2_17D(v)  (((v)-2)<<24) // 对于使能了同步突发模式的 NOR Flash，该位定义了获取首个数据前要发送给存储器的存储器时钟周期数 (+2)，该时序参数以 Flash 时钟 (CLK) 周期而非 HCLK 周期表示。在异步 NOR Flash、 SRAM或 ROM 访问模式下，该值为无关值。如果是 CRAM，该字段必须设置为“0”
#define FSMC_B1_ByTRx_ACCMOD_A           (0x0U<<28)    // 访问模式A，EXTMOD=1时，该字段才有效
#define FSMC_B1_ByTRx_ACCMOD_B           (0x1U<<28)
#define FSMC_B1_ByTRx_ACCMOD_C           (0x2U<<28)
#define FSMC_B1_ByTRx_ACCMOD_D           (0x3U<<28)


#endif /* _FSMC_HW_H_ */
